package com.vlong.town.util.config.database;

import java.sql.SQLException;

import javax.sql.DataSource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;

/**
 * Druid数据库连接池配置
 * @author Assassin
 */
@Configuration
public class DataSourceConfig {

    // 日志记录
    private Logger logger = LoggerFactory.getLogger(DataSourceConfig.class);

    @Value("${spring.datasource.type}")
    private String dataSourceType;// 连接池类型

    @Value("${spring.datasource.driver-class-name}")
    private String driverClassName;// JDBC驱动名称

    @Value("${spring.datasource.url}")
    private String dataBaseUrl;// 数据库URL

    @Value("${spring.datasource.username}")
    private String dataBaseUserName;// 数据库用户名

    @Value("${spring.datasource.password}")
    private String dataBasePassword;// 数据库密码

    @Value("${spring.datasource.initialSize}")
    private int initialSize;// 初始化连接数

    @Value("${spring.datasource.maxActive}")
    private int maxActive;// 最大并发连接数

    @Value("${spring.datasource.minIdle}")
    private int minIdle;// 最小空闲连接数

    @Value("${spring.datasource.maxWait}")
    private int maxWait;// 获取连接等待超时时间

    @Value("${spring.datasource.timeBetweenEvictionRunsMillis}")
    private int timeBetweenEvictionRunsMillis;// 间隔多久才进行一次检测，检测需要关闭的空闲连接

    @Value("${spring.datasource.minEvictableIdleTimeMillis}")
    private int minEvictableIdleTimeMillis;// 一个连接在池中最小生存的时间

    @Value("${spring.datasource.validationQuery}")
    private String validationQuery;// 检测连接是否有效的sql语句

    @Value("${spring.datasource.testWhileIdle}")
    private boolean testWhileIdle;// 申请连接的时候检测，如果空闲时间大于timeBetweenEvictionRunsMillis，执行validationQuery检测连接是否有效，不影响性能，并且保证安全性

    @Value("${spring.datasource.testOnBorrow}")
    private boolean testOnBorrow;// 申请连接时执行validationQuery检测连接是否有效，配置会降低性能

    @Value("${spring.datasource.testOnReturn}")
    private boolean testOnReturn;// 归还连接时执行validationQuery检测连接是否有效，配置会降低性能

    @Value("${spring.datasource.poolPreparedStatements}")
    private boolean poolPreparedStatements;// 是否缓存preparedStatement，也就是PSCache。PSCache对支持游标的数据库性能提升巨大，比如说oracle。在mysql下建议关闭

    @Value("${spring.datasource.filters}")
    private String filters;// 属性类型是字符串，通过别名的方式配置扩展插件，常用的插件有：监控统计用的filter:stat日志用的filter:log4j防御sql注入的filter:wall

    @Value("${spring.datasource.connectionProperties}")
    private String connectionProperties;// 配置连接的各项属性

    @Value("${spring.datasource.useGlobalDataSourceStat}")
    private boolean useGlobalDataSourceStat;// 合并多个DruidDataSource的监控数据

    @Value("${spring.datasource.druidLoginName}")
    private String druidLoginName;// 登录druid的账号

    @Value("${spring.datasource.druidPassword}")
    private String druidPassword;// 登录druid的密码

    @Bean
    @Primary
    public DataSource dataSource() {
        DruidDataSource datasource = new DruidDataSource();
        try {
            datasource.setDbType(this.dataSourceType);
            datasource.setDriverClassName(this.driverClassName);
            datasource.setUrl(this.dataBaseUrl);
            datasource.setUsername(this.dataBaseUserName);
            datasource.setPassword(this.dataBasePassword);
            datasource.setInitialSize(this.initialSize);
            datasource.setMaxActive(maxActive);
            datasource.setMinIdle(minIdle);
            datasource.setMaxWait(maxWait);
            datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
            datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
            datasource.setValidationQuery(validationQuery);
            datasource.setTestWhileIdle(testWhileIdle);
            datasource.setTestOnBorrow(testOnBorrow);
            datasource.setTestOnReturn(testOnReturn);
            datasource.setPoolPreparedStatements(poolPreparedStatements);
            datasource.setFilters(filters);
            datasource.setConnectionProperties(connectionProperties);
            datasource.setUseGlobalDataSourceStat(useGlobalDataSourceStat);
        } catch (SQLException e) {
            logger.error("Druid Configuration Initialization Filter", e);
        }
        return datasource;
    }

    @Bean
    public ServletRegistrationBean servletRegistrationBean() {
        ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean();
        servletRegistrationBean.setServlet(new StatViewServlet());
        servletRegistrationBean.addUrlMappings("/druid/*");  // url 匹配
        servletRegistrationBean.addInitParameter("allow", "127.0.0.1"); // IP白名单 (没有配置或者为空，则允许所有访问)
        servletRegistrationBean.addInitParameter("deny", ""); // IP黑名单 (存在共同时，deny优先于allow)
        servletRegistrationBean.addInitParameter("loginUsername", this.druidLoginName);// 登录账号
        servletRegistrationBean.addInitParameter("loginPassword", this.druidPassword);// 登录密码
        servletRegistrationBean.addInitParameter("resetEnable", "false"); // 禁用HTML页面上的“Reset All”功能
        return servletRegistrationBean;
    }

    @Bean(name = "druidWebStatFilter")
    public FilterRegistrationBean filterRegistrationBean() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(new WebStatFilter());
        filterRegistrationBean.addUrlPatterns("/*");
        filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");// 忽略资源
        filterRegistrationBean.addInitParameter("profileEnable", "true");
        filterRegistrationBean.addInitParameter("principalCookieName", "USER_COOKIE");
        filterRegistrationBean.addInitParameter("principalSessionName", "USER_SESSION");
        return filterRegistrationBean;
    }
}